#include <rtthread.h>
#include <rthw.h>

extern struct rt_thread *rt_current_thread;
extern rt_uint32_t rt_thread_ready_priority_group;
extern rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
extern rt_list_t rt_thread_defunct;

void rt_thread_exit(){
    rt_thread_t thread;
    rt_ubase_t tmp;

    thread = rt_thread_self();

    tmp = rt_hw_interrupt_disable();

    rt_schedule_remove_thread(thread);

    thread->stat = RT_THREAD_CLOSE;

    /* 分离定时器 */
    rt_timer_detach(&thread->thread_timer);

    /* 判断是否是静态类型，若是动态创建的会执行相应的清理函数，这里未实现 */
    if(rt_object_is_systemobject((rt_object_t)thread)){
        rt_object_detach((rt_object_t)thread);
    }else{
        /* 如果是动态创建的则释放对象内存 */
        rt_object_delete((rt_object_t)thread);
    }

    rt_hw_interrupt_enable(tmp);
    
    printf("+++++++++++++ [thread_exit] %s------------- \r\n", thread->name);

    rt_schedule();
}

static rt_err_t _rt_thread_init(struct rt_thread *thread,
                                const char *name,
                                void (*entry)(void *parameter),
                                void *parameter,
                                void *stack_start,
                                rt_uint32_t stack_size,
                                rt_uint8_t priority,
                                rt_uint32_t tick){

    rt_list_init(&thread->tlist);

    thread->entry = (void *)entry;
    thread->parameter = parameter;

    thread->stack_addr = stack_start;
	thread->stack_size = stack_size;

    thread->sp = rt_hw_stack_init(thread->entry, thread->parameter,
                                    (void *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)),
                                    (void *)rt_thread_exit);

    thread->init_priority = priority;
    thread->current_priority = priority;
    thread->number_mask = 0;
    
    thread->init_tick = tick;
    thread->remaining_tick = tick;

    thread->error = RT_EOK;
    thread->stat = RT_THREAD_INIT;

#if defined(RT_USING_EVENT)
    thread->event_set = 0;
    thread->event_info = 0;
#endif

    rt_timer_init(&thread->thread_timer,
                    thread->name,
                    rt_thread_timeout,
                    thread,
                    0,
                    RT_TIMER_FLAG_ONE_SHOT);

    return RT_EOK;

}

rt_err_t rt_thread_init(struct rt_thread *thread,
                        const char       *name,
                        void (*entry)(void *parameter),
                        void             *parameter,
                        void             *stack_start,
                        rt_uint32_t       stack_size,
                        rt_uint8_t          priority,
                        rt_uint32_t          tick)
{
    /* 线程对象初始化 */
	/* 线程结构体开头部分的成员就是rt_object_t类型 */
    rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
    
	return _rt_thread_init(thread, name, entry, parameter, stack_start, stack_size, priority, tick);

}

rt_thread_t rt_thread_create(const char *name,
                            void (*entry)(void *parameter),
                            void *parameter,
                            rt_uint32_t stack_size,
                            rt_uint8_t priority,
                            rt_uint32_t tick){
    
    rt_thread_t thread;
    void *stack_start;

    thread = (rt_thread_t)rt_object_allocate(RT_Object_Class_Thread, name);
    if(thread == RT_NULL){
        // printf("thread: 0x%x\r\n", thread);
        return RT_NULL;
    }

    stack_start = (void *)rt_malloc(stack_size);
    if(stack_start == RT_NULL){
        rt_object_delete((rt_object_t)thread);

        return RT_NULL;
    }

    _rt_thread_init(thread, name, entry, parameter, stack_start, stack_size, priority, tick);

    return thread;
}

rt_err_t rt_thread_delete(rt_thread_t thread){
    rt_base_t lock;

    RT_ASSERT(thread != RT_NULL);

    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
    {
        /* remove from schedule */
        rt_schedule_remove_thread(thread);
    }

    rt_timer_detach(&thread->thread_timer);

    /* change stat */
    thread->stat = RT_THREAD_CLOSE;

    /* disable interrupt */
    lock = rt_hw_interrupt_disable();

    /* insert to defunct thread list */
    rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));

    /* enable interrupt */
    rt_hw_interrupt_enable(lock);

    return RT_EOK;
}

/**
 * 该函数用于挂起指定的线程
 * @param thread 要被挂起的线程
 *
 * @return 操作状态, RT_EOK on OK, -RT_ERROR on error
 *
 * @note 如果挂起的是线程自身，在调用该函数后，
 * 必须调用rt_schedule()进行系统调度
 * 
 */
rt_err_t rt_thread_suspend(rt_thread_t thread)
{
    register rt_base_t temp;


    /* 只有就绪的线程才能被挂起，否则退出返回错误码 */
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY)
    {
        return -RT_ERROR;
    }

    /* 关中断 */
    temp = rt_hw_interrupt_disable();

    /* 改变线程状态 */
    thread->stat = RT_THREAD_SUSPEND;
    /* 将线程从就绪列表删除 */
    rt_schedule_remove_thread(thread);

    /* 停止线程定时器 */
    rt_timer_stop(&(thread->thread_timer));

    /* 开中断 */
    rt_hw_interrupt_enable(temp);

    return RT_EOK;
}


/**
 * 该函数将让当前线程睡眠一段时间，单位为tick
 * 
 * @param tick 睡眠时间，单位为tick
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_sleep(rt_tick_t tick)
{
    register rt_base_t temp;
    struct rt_thread *thread;
    
    /* 关中断 */
    temp = rt_hw_interrupt_disable();
    
    /* 获取当前线程的线程控制块 */
    thread = rt_current_thread;

    /* 挂起线程 */
    rt_thread_suspend(thread);

    /* 设置线程定时器的超时时间 */
    rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);
    
    /* 启动定时器 */
    rt_timer_start(&(thread->thread_timer));

    /* 开中断 */
    rt_hw_interrupt_enable(temp);

    /* 执行系统调度 */
    rt_schedule();

    return RT_EOK;
}

/* 延时函数 */
rt_err_t rt_thread_delay(rt_tick_t tick)
{
    return rt_thread_sleep(tick);
}


rt_thread_t rt_thread_self(void)
{
    return rt_current_thread;
}


/**
 * 启动一个线程并将其放到系统的就绪列表中
 * 
 * @param thread 待启动的线程
 *
 * @return 操作状态, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_startup(rt_thread_t thread)
{
    /* 设置当前优先级为初始优先级 */
    thread->current_priority = thread->init_priority;
    thread->number_mask = 1L << thread->current_priority;
    
    /* 改变线程的状态为挂起状态 */
    thread->stat = RT_THREAD_SUSPEND;
    /* 然后恢复线程 */
    rt_thread_resume(thread);
    
    if (rt_thread_self() != RT_NULL)
    {
        /* 系统调度 */
        rt_schedule();
    }

    return RT_EOK;
}

/**
 * 该函数用于恢复一个线程然后将其放到就绪列表
 *
 * @param thread 需要被恢复的线程
 *
 * @return 操作状态, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_resume(rt_thread_t thread)
{
    register rt_base_t temp;
    
    /* 将被恢复的线程必须在挂起态，否则返回错误码 */
    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
    {
        return -RT_ERROR;
    }

    /* 关中断 */
    temp = rt_hw_interrupt_disable();

    /* 从挂起队列移除 */
    rt_list_remove(&(thread->tlist));

    /* 开中断 */
    rt_hw_interrupt_enable(temp);

    /* 插入就绪列表 */
    rt_schedule_insert_thread(thread);

    return RT_EOK;
}

/**
 * 线程超时函数
 * 当线程延时到期或者等待的资源可用或者超时时，该函数会被调用
 *
 * @param parameter 超时函数的形参
 */
void rt_thread_timeout(void *parameter)
{
    struct rt_thread *thread;

    thread = (struct rt_thread *)parameter;

    /* 设置错误码为超时 */
    thread->error = -RT_ETIMEOUT;

    /* 将线程从挂起列表中删除 */
    rt_list_remove(&(thread->tlist));

    /* 将线程插入到就绪列表 */
    rt_schedule_insert_thread(thread);

    /* 系统调度 */
    rt_schedule();
}


/**
 * 该函数将让当前线程让出处理器，调度器选择最高优先级的线程运行。当前让出处理器之后，
 * 当前线程还是在就绪态。
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_yield(void)
{
    register rt_base_t level;
    struct rt_thread *thread;

    /* 关中断 */
    level = rt_hw_interrupt_disable();

    /* 获取当前线程的线程控制块 */
    thread = rt_current_thread;
    
    /* 如果线程在就绪态，且同一个优先级下不止一个线程 */
    if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY &&
        thread->tlist.next != thread->tlist.prev)
    {
        /* 将时间片耗完的线程从就绪列表移除 */
        rt_list_remove(&(thread->tlist));
        
        /* 将线程插入到该优先级下的链表的尾部 */
        rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
                              &(thread->tlist));

        /* 开中断 */
        rt_hw_interrupt_enable(level);

        /* 执行调度 */
        rt_schedule();

        return RT_EOK;
    }

    /* 开中断 */
    rt_hw_interrupt_enable(level);

    return RT_EOK;
}


rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg){
    rt_base_t tmp;

    RT_ASSERT(thread != RT_NULL);

    switch (cmd)
    {
        case RT_THREAD_CTRL_STARTUP:
            return rt_thread_startup(thread);
            break;

        case RT_THREAD_CTRL_CLOSE:
            return rt_thread_delete(thread);
            break;

        case RT_THREAD_CTRL_CHANGE_PRIORITY:
            tmp = rt_hw_interrupt_disable();

            if((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY){
                rt_schedule_remove_thread(thread);

                thread->current_priority = *(rt_uint8_t *)arg;
                thread->number_mask = 1 << thread->current_priority;

                rt_schedule_insert_thread(thread);
            }else{
                thread->current_priority = *(rt_uint8_t *)arg;
                thread->number_mask = 1 << thread->current_priority;
            }

            rt_hw_interrupt_enable(tmp);

            break;
    }

    return RT_EOK;
}